﻿using MarkdownSharp;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.FileProviders;
using System.Text;
using Ude;

namespace Markdown中间件
{
    /**
     *  需求
     *  markdown不被浏览器支持,所以编写一个在服务器端把Markdown转换为html的中间件
     */
    public class MarkdownMiddleware
    {
        private readonly RequestDelegate next;
        private readonly IWebHostEnvironment env;
        private readonly IMemoryCache memCache;

        public MarkdownMiddleware(RequestDelegate next, IWebHostEnvironment env, IMemoryCache memCache)
        {
            this.next = next;
            this.env = env;
            this.memCache = memCache;
        }

        /// <summary>
        /// 检测流的编码
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        private static string DetectCharset(Stream stream)
        {
            CharsetDetector charDetector = new();
            charDetector.Feed(stream);
            charDetector.DataEnd();
            string charset = charDetector.Charset ?? "UTF-8";
            stream.Position = 0;
            return charset;
        }

        /// <summary>
        /// 读取文本内容
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        private static async Task<string> ReadText(Stream stream)
        {
            string charset = DetectCharset(stream);
            using var reader = new StreamReader(stream, Encoding.GetEncoding(charset));
            return await reader.ReadToEndAsync();
        }

        public async Task InvokeAsync(HttpContext context)
        {
            string path = context.Request.Path.Value ?? "";
            if (!path.EndsWith(".md"))
            {
                await next(context);
                return;
            }

            IFileInfo file = env.WebRootFileProvider.GetFileInfo(path);
            if (!file.Exists)
            {
                await next(context);
                return;
            }

            context.Response.ContentType = $"text/html;charset=UTF-8";
            context.Response.StatusCode = 200;
            string cachekey = nameof(MarkdownMiddleware) + path + file.LastModified;
            var html = await memCache.GetOrCreateAsync(cachekey, async ce =>
            {
                ce.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1);
                using var stream = file.CreateReadStream();
                string text = await ReadText(stream);
                Markdown markdown = new Markdown();
                return markdown.Transform(text);

            });

            await context.Response.WriteAsync(html);
        }
    }
}
